﻿using System;
using UnityEditor;
using UnityEngine;

namespace ProjScan.GUIExtensions
{
    //
    // 摘要:
    //     This entry class just uses EditorGUILayout.PropertyField to draw a given property.
    //     This is the basic way to use GUITable. It will draw the properties the same way
    //     Unity would by default.
    public class PropertyEntry : TableEntry
    {
        private SerializedProperty sp;

        private SerializedObject so;

        private string propertyPath;

        public override string comparingValue
        {
            get
            {
                if (sp != null)
                {
                    switch (sp.propertyType)
                    {
                        case SerializedPropertyType.String:
                        case SerializedPropertyType.Character:
                            return sp.stringValue.ToString();
                        case SerializedPropertyType.Float:
                            return sp.doubleValue.ToString();
                        case SerializedPropertyType.Integer:
                        case SerializedPropertyType.LayerMask:
                        case SerializedPropertyType.ArraySize:
                            return sp.intValue.ToString();
                        case SerializedPropertyType.Enum:
                            return sp.enumValueIndex.ToString();
                        case SerializedPropertyType.Boolean:
                            return sp.boolValue.ToString();
                        case SerializedPropertyType.ObjectReference:
                            return sp.objectReferenceValue.name.ToString();
                        case SerializedPropertyType.ExposedReference:
                            return sp.exposedReferenceValue.name.ToString();
                    }
                }

                return "";
            }
        }

        public override void DrawEntry(float width, float height)
        {
            if (sp != null)
            {
                EditorGUILayout.PropertyField(sp, GUIContent.none, GUILayout.Width(width), GUILayout.Height(height));
                so.ApplyModifiedProperties();
            }
            else
            {
                Debug.LogWarningFormat("Property not found: {0} -> {1}", so.targetObject.name, propertyPath);
                GUILayout.Space(width + 4f);
            }
        }

        public override int CompareTo(object other)
        {
            TableEntry tableEntry = (TableEntry)other;
            if (tableEntry == null)
            {
                throw new ArgumentException("Object is not a GUITableEntry");
            }

            PropertyEntry propertyEntry = (PropertyEntry)other;
            if (propertyEntry == null)
            {
                return base.CompareTo(other);
            }

            SerializedProperty serializedProperty = propertyEntry.sp;
            if (sp.propertyType != serializedProperty.propertyType)
            {
                return base.CompareTo(other);
            }

            if (sp != null)
            {
                switch (sp.propertyType)
                {
                    case SerializedPropertyType.String:
                    case SerializedPropertyType.Character:
                        return sp.stringValue.CompareTo(serializedProperty.stringValue);
                    case SerializedPropertyType.Float:
                        return sp.doubleValue.CompareTo(serializedProperty.doubleValue);
                    case SerializedPropertyType.Integer:
                    case SerializedPropertyType.LayerMask:
                    case SerializedPropertyType.ArraySize:
                        return sp.intValue.CompareTo(serializedProperty.intValue);
                    case SerializedPropertyType.Enum:
                        return sp.enumValueIndex.CompareTo(serializedProperty.enumValueIndex);
                    case SerializedPropertyType.Boolean:
                        return sp.boolValue.CompareTo(serializedProperty.boolValue);
                    case SerializedPropertyType.ObjectReference:
                        return sp.objectReferenceValue.name.CompareTo(serializedProperty.objectReferenceValue.name);
                    case SerializedPropertyType.ExposedReference:
                        return sp.exposedReferenceValue.name.CompareTo(serializedProperty.exposedReferenceValue.name);
                }
            }

            return 0;
        }

        public PropertyEntry(SerializedProperty property)
        {
            sp = property;
            so = property.serializedObject;
            propertyPath = property.propertyPath;
        }

        public PropertyEntry(SerializedObject so, string propertyPath)
        {
            this.so = so;
            this.propertyPath = propertyPath;
            sp = so.FindProperty(propertyPath);
        }
    }
}